package wiki.old.cs236703.Wiki;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Map;

import wiki.old.cs236703.Wiki.ContentRanker.QueryException;


public abstract class AbstractWikiContentManager {
	protected Map<ContentType, ContentProcessor> contentProcessorMap = 
		new EnumMap<ContentType, ContentProcessor>(ContentType.class);
	protected ContentRanker contentRanker;
	
	public enum ContentAttributes{
		AUTHOR,
		LANGUAGE,
		DATE
	}
		
	public interface WikiContent{	
		public String name();		
		public void setName(String name);
		public byte[] content();
		public void setContent(byte[] content, String contentType);
		public int revision();	
		public Map<ContentAttributes, String> getAttributes();
		public void setAttributes(Map<ContentAttributes, String> attributes);
		public String getAttribute(ContentAttributes key);
		public void setAttribute(ContentAttributes key, String value);
	}
	
	public class SearchResult{ 
		final public int rank;
		final public WikiContent result;
		
		public SearchResult(int rank, WikiContent result){
			this.rank = rank;
			this.result = result;
		}
	}
	
	/**
	 * Initializing the content manager.
	 * @param cps an array with all the content processors.
	 * @param crs an array with all the content rankers available.
	 * @note Must be called before any other action. 
	 */
	public void initialize(ContentProcessor[] cps, ContentRanker cr){
		for (ContentProcessor cp: cps)
			contentProcessorMap.put(cp.getHandledContentType(), cp);
		contentRanker = cr;
	}	
	/**
	 * Returns a Wiki content with name if present in the Data Source. if not 
	 * present then creates a new Wiki content in the Data Source with name and 
	 * revision 0.
	 * @param name the Wiki content name to be retrived.
	 * @return a Wiki content with name.
	 */
	public abstract WikiContent getWikiContent(String name);
	
	/**
	 * Returns whether a Wiki content with name is present in the data source. 
	 * @param name the Wiki content name to be checked.
	 * @return true if a Wiki content with name is present in the Data Source, 
	 * false otherwise.
	 */
	public abstract boolean hasWikiContent(String name);
	
	/**
	 * Search for matching contents in the Data Source. uses contentRankerMap 
	 * in order to rank each search entry.	
	 * @param query the query to be run.
	 * @return an array list of suitable search results.
	 * @throws QueryException 
	 */
	public abstract ArrayList<SearchResult> search(String query) throws QueryException;
	
	/**
	 * Update a Wiki content in the Data Source, creates a new revision of the 
	 * content, and advances the revision counter.
	 * @param c a Wiki content to be updated in the data source.
	 * @return The new updated content from the data source.
	 */
	public abstract WikiContent update(WikiContent c);
	
	/**
	 * check if the content is valid Data Source, meaning that the content 
	 * revision is equal to the current revision in the data source.
	 * @param c a Wiki content to be checked.
	 * @return true if the content revision is equal to the current revision 
	 * in the data source. false otherwise.
	 */
	public abstract boolean isWikiContentValid(WikiContent c);
	
	/**
	 * Thrown when the target revision in out of bounds or the Wiki content is 
	 * missing from the data source.
	 */
	public static class RollBackException extends Exception{		
		private static final long serialVersionUID = 6472876648852975853L;
	}
	
	/**
	 * roll back to target revision in the Data Source.
	 * @param c a Wiki content to be rolled back.
	 * @param targetRevision the target revision to be rolled back to. must be
	 * positive (>0) and smaller then the current revision in the database. 
	 * @return The wiki content with the target revision.
	 * @throws RollBackException if the target revision in out of bounds or the 
	 * Wiki content is missing from the data source.
	 */
	public abstract WikiContent rollBackToRevision(WikiContent c, int targetRevision) throws RollBackException;
}
